package com.mycompany.project.client;

import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.user.client.Random;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class StockWatcher implements EntryPoint {
	
	private static final int REFRESH_INTERVAL = 5000;
	
	private Image image;
	private Label lblStockWatcher;
	private FlexTable stocksFlexTable;
	private TextBox newSymbolTextBox;
	private HorizontalPanel addPanel;
	private Button addButton;
	private Label lastUpdateLabel;
	
	private ArrayList<String> stocks = new ArrayList<String>();
	private StockPriceServiceAsync stockPriceSvc = GWT.create(StockPriceService.class);
	
	public void onModuleLoad() {
		RootPanel rootPanel = RootPanel.get();
		
		VerticalPanel verticalPanel = new VerticalPanel();
		rootPanel.add(verticalPanel, 0, 0);
		verticalPanel.setSize("371px", "480px");
		{
			image = new Image("googlecode.png");
			verticalPanel.add(image);
		}
		{
			lblStockWatcher = new Label("Stock Watcher");
			lblStockWatcher.setStyleName("gwt-Label-StockWatcher");
			verticalPanel.add(lblStockWatcher);
		}
		{
			stocksFlexTable = new FlexTable();
			stocksFlexTable.setText(0, 0, "Symbol");
			stocksFlexTable.setText(0, 1, "Price");
			stocksFlexTable.setText(0, 2, "Change");
			stocksFlexTable.setText(0, 3, "Remove");
			
			stocksFlexTable.setCellPadding(6);
			stocksFlexTable.addStyleName("watchList");
			stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader");
			stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn");
			stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn");
			stocksFlexTable.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn");
			verticalPanel.add(stocksFlexTable);
		}
		{
			addPanel = new HorizontalPanel();
			verticalPanel.add(addPanel);
			addPanel.addStyleName("addPanel");
			{
				newSymbolTextBox = new TextBox();
				newSymbolTextBox.setFocus(true);
				newSymbolTextBox.addKeyPressHandler(new KeyPressHandler() {
					public void onKeyPress(KeyPressEvent event) {
						if (event.getCharCode() == KeyCodes.KEY_ENTER) {
							addStock();
						}
					}
				});
				addPanel.add(newSymbolTextBox);
			}
			{
				addButton = new Button("Add");
				addButton.setStyleName("gwt-Button-Add");
				addButton.addClickHandler(new ClickHandler() {
					public void onClick(ClickEvent event) {
						addStock();
					}
				});
				addPanel.add(addButton);
			}
		}
		{
			lastUpdateLabel = new Label("New label");
			verticalPanel.add(lastUpdateLabel);
		}
		
		Timer refreshTimer = new Timer() {
			@Override
			public void run() {
				refreshWatchList();
			}			
		};
		refreshTimer.scheduleRepeating(REFRESH_INTERVAL);
	}
	
	protected void refreshWatchList() {
		if (stockPriceSvc == null) {
			stockPriceSvc = GWT.create(StockPriceService.class);
		}
		
		AsyncCallback<StockPrice[]> callback = new AsyncCallback<StockPrice[]>() {
			@Override
			public void onFailure(Throwable caught) {}

			@Override
			public void onSuccess(StockPrice[] result) {
				updateTable(result);
			}
		};
		
		stockPriceSvc.getPrices(stocks.toArray(new String[0]), callback);
	}
	
	private void updateTable(StockPrice[] prices) {
		for (int i = 0; i < prices.length; i++)
		{
			updateTable(prices[i]);
		}

		// change the last update timestamp
		lastUpdateLabel.setText("Last update : "
			+ DateTimeFormat.getMediumDateTimeFormat().format(new Date()));
	}

	private void updateTable(StockPrice stockPrice) {
		// make sure the stock is still in our watch list
		if (!stocks.contains(stockPrice.getSymbol()))
		{
			return;
		}

		int row = stocks.indexOf(stockPrice.getSymbol()) + 1;

		// Format the data in the Price and Change fields.
		String priceText = NumberFormat.getFormat("#,##0.00").format(stockPrice.getPrice());
		NumberFormat changeFormat = NumberFormat.getFormat("+#,##0.00;-#,##0.00");
		String changeText = changeFormat.format(stockPrice.getChange());
		String changePercentText = changeFormat.format(stockPrice.getChangePercent());

		// Populate the Price and Change fields with new data.
		stocksFlexTable.setText(row, 1, priceText);
		Label changeWidget = (Label)stocksFlexTable.getWidget(row, 2);
		changeWidget.setText(changeText + " (" + changePercentText + "%)");
		String changeStyleName = "noChange";
		if (stockPrice.getChangePercent() < -0.1f) {
			changeStyleName = "negativeChange";
		}
		else if (stockPrice.getChangePercent() > 0.1f) {
			changeStyleName = "positiveChange";
		}
		changeWidget.setStyleName(changeStyleName);
	}

	protected void addStock() {
		final String symbol = newSymbolTextBox.getText().toUpperCase().trim();
		newSymbolTextBox.setFocus(true);
		 
		// symbol must be between 1 and 10 chars that are numbers, letters, or dots
		if (!symbol.matches("^[0-9a-zA-Z\\.]{1,10}$"))
		{
		    Window.alert("'" + symbol + "' is not a valid symbol.");
		    newSymbolTextBox.selectAll();
		    return;
		}
			 
		newSymbolTextBox.setText("");
			     
		// don't add the stock if it's already in the watch list
	    if (stocks.contains(symbol))
	        return;

	    // add the stock to the list
	    int row = stocksFlexTable.getRowCount();
	    stocks.add(symbol);
	    stocksFlexTable.setText(row, 0, symbol);
	    stocksFlexTable.setWidget(row, 2, new Label());
	    stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericColumn");
	    stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericColumn");
	    stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColumn");

	    // add button to remove this stock from the list
	    Button removeStock = new Button("x");
	    removeStock.addStyleDependentName("remove");
	    removeStock.addClickHandler(new ClickHandler() {
	    public void onClick(ClickEvent event) {					
	        int removedIndex = stocks.indexOf(symbol);
	        stocks.remove(removedIndex);
	        stocksFlexTable.removeRow(removedIndex + 1);
	    }
	    });
	    stocksFlexTable.setWidget(row, 3, removeStock);
	}
}
